#include "Svn.h"
#include "svn_version.h"

//#pragma comment(linker, "\"/manifestdependency:type='Win32' name='Microsoft.VC80.CRT' version='8.0.50608.0' processorArchitecture='X86' publicKeyToken='1fc8b3b9a1e18e3b' language='*'\"")

IronSvn::Svn::Svn()
{
}

String^ IronSvn::Svn::GetError(svn_error_t* error)
{
	String^ result = nullptr;
	if (error)
	{
		result = gcnew String(error->message);
		error = error->child;
		while (error)
		{
			result += ": " + gcnew String(error->message);
			error = error->child;
		}
	}
	return result;
}

void IronSvn::Svn::ThrowIfError(svn_error_t* error)
{
	String^ msg = IronSvn::Svn::GetError(error);
	if (msg != nullptr && msg->Length > 0)
	{
		throw gcnew IronSvn::SvnException(msg);
	}
}

IronSvn::SvnVersion^ IronSvn::Svn::GetVersion()
{
	SvnVersion^ result = gcnew SvnVersion();
	const svn_version_t* v = svn_subr_version();
	result->Tag = gcnew String(v->tag);
	result->Major = v->major;
	result->Minor = v->minor;
	result->Patch = v->patch;
	return result;
}

String^ IronSvn::Svn::EnsureLocalPath(String^ path)
{
	if (path != nullptr)
	{
		if (path->ToLower()->StartsWith("file:///"))
		{
			path = path->Substring(8)->Replace('/', '\\');
		}
	}
	return path;
}

String^ IronSvn::Svn::PreparePath(String^ path)
{
#ifdef LOGS
	if (IronSvn::Svn::IsLogEnabled) Debug::WriteLine(String::Format("> PreparePath {0}", path));
#endif

	if (path == nullptr)
	{
		throw gcnew ArgumentException("Local path not specified");
	}
	path = path->Trim();
	path = path->Replace('\\', '/');
	while (path->EndsWith("/"))
	{
		path = path->Substring(0, path->Length - 1);
	}

#ifdef LOGS
	if (IronSvn::Svn::IsLogEnabled) Debug::WriteLine(String::Format("< PreparePath {0}", path));
#endif

	return path;
}

apr_array_header_t* IronSvn::Svn::GetStringAsAprArray(const char *str, apr_pool_t *pool)
{
	apr_array_header_t* targets = apr_array_make(pool, 1, sizeof(const char *));
	const char* target = apr_pstrdup(pool, str);
	APR_ARRAY_PUSH(targets, const char *) = target;
	return targets;
}

DateTime^ IronSvn::Svn::ConvertAprTimeToDateTime(apr_time_t time)
{
	// returns UTC DateTime
	DateTime^ dt = gcnew DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind::Utc);
	// apr_time_t is micro seconds, so we convert to milli
	return dt->AddMilliseconds(((double)time)/1000);
}

String^ IronSvn::Svn::SvnPathJoin(String^ base, String^ component)
{
	if (String::IsNullOrEmpty(base) && String::IsNullOrEmpty(component))
	{
		throw gcnew ArgumentNullException("both strings null");
	}
	if (String::IsNullOrEmpty(component))
	{
		return base;
	}
	else if (String::IsNullOrEmpty(base))
	{
		return component;
	}

	base = IronSvn::Svn::PreparePath(base);
	component = IronSvn::Svn::PreparePath(component);

	if (component[0] == '/')
	{
		return component;
	}

	if (base->Length > 0 && base[base->Length - 1] == '/')
	{
		base = base->Substring(0, base->Length - 1);
	}

	return base + "/" + component;
}
